using System;
using System.Collections.Generic;
using System.Text;

using XGAE.Framework;
using XGAE.Framework.Extensions;
using xServ = XGAE.Framework.Services;
using xBody = XGAE.Framework.Body;

using XNAF = Microsoft.Xna.Framework;

namespace XGAE.Abilities.Navigation
{
    interface INavigationInterface
    {
        NavigationModule Self { get; }

        /// <summary>
        /// Wrappers to retrieve the motion from the module.  
        /// </summary>
        xBody.Motion.IRelative GetMotion();

        /// <summary>
        /// Wrappers to retrieve the physics from the module. 
        /// </summary>
        xBody.Physics.IRelative GetPhysics();

        /// <summary>
        /// Wrappers to retrieve the state from the module.
        /// </summary>
        xBody.Physics.IState GetState();

        /// <summary>
        /// Wrappers to retrieve the space from the module. 
        /// </summary>
        xBody.Vision.ISpace GetSpace();

        /// <summary>
        /// Wrappers to retrieve the visual from the module.
        /// </summary>
        xBody.Vision.ISymbolic GetVisual();

        /// <summary>
        /// Wrappers to retrieve the debug from the module.
        /// </summary>
        xServ.Debug.IVisual GetDebug();
    }

    /// <summary>
    /// Provides facilities for basic navigation.
    /// </summary>
    class NavigationSimple : Interface, Abilities.Navigation.ISimple, INavigationInterface
    {
        #region C'tors

        /// <summary>
        /// Constructor called by the module when it creates a new interface.
        /// </summary>
        /// <param name="m"></param>
        public NavigationSimple(NavigationModule m)
            : base("Simple", 0x0002)
        {
            this._self = m;
        }

        #endregion

        #region ISimple Implementation

        /// <summary>
        /// Move around seemingly randomly while avoiding obstacles.
        /// </summary>
        public void Wander()
        {
            if (this._self.Mode != Mode.Wandering)
            {
                this._self.Travel = -this._self.Orientation.Yaw;
            }
            this._self.Mode = Mode.Wandering;
        }

       /// <summary>
       /// Halt the movement and keep the body completely still.
       /// </summary>
        public void Stop()
        {
            this._self.Mode = Mode.Stopped;
        }

        /// <summary>
        /// Attempt to move towards a point in space.
        /// </summary>
        /// <param name="target"></param>
        public void Seek(XNAF.Vector3 target)
        {
            this._self.Mode = Mode.Seeking;
            this._self.Target = target;
        }

        /// <summary>
        /// Move away from a particular point in space.
        /// </summary>
        /// <param name="source"></param>
        public void Flee(XNAF.Vector3 source)
        {
            this._self.Mode = Mode.Fleeing;
            this._self.Target = source;
        }

        /// <summary>
        /// Pass back the direction of travel.
        /// </summary>
        /// <returns></returns>
        public Angles GetHeading()
        {
            return new Angles
                (-this._self.Orientation.Pitch,
                -this._self.Orientation.Yaw - this._self.Travel, 0.0f);
        }

        #endregion

        #region INavigationInterface Implementation

        // reference to the owner component
        protected NavigationModule _self;

        public NavigationModule Self
        {
            get { return this._self; }
        }

        /// <summary>
        /// Wrappers to retrieve the motion from the module.  
        /// </summary>
        public xBody.Motion.IRelative GetMotion()
        {
            return this._self.Motion;
        }

        /// <summary>
        /// Wrappers to retrieve the physics from the module. 
        /// </summary>
        public xBody.Physics.IRelative GetPhysics()
        {
            return this._self.Physics;
        }

        /// <summary>
        /// Wrappers to retrieve the state from the module.
        /// </summary>
        public xBody.Physics.IState GetState()
        {
            return this._self.State;
        }

        /// <summary>
        /// Wrappers to retrieve the space from the module. 
        /// </summary>
        public xBody.Vision.ISpace GetSpace()
        {
            return this._self.Space;
        }

        /// <summary>
        /// Wrappers to retrieve the visual from the module.
        /// </summary>
        public xBody.Vision.ISymbolic GetVisual()
        {
            return this._self.Visual;
        }

        /// <summary>
        /// Wrappers to retrieve the debug from the module.
        /// </summary>
        public xServ.Debug.IVisual GetDebug()
        {
            return this._self.Debug;
        }

        #endregion
    }

    
    /// <summary>
    /// Allow the other sensor and effector modules to convert relative commands into absolute
    /// world coordinates. 
    /// </summary>
    class NavigationConversion : Interface, xBody.Physics.IConversion, INavigationInterface
    {
        #region C'tors

        /// <summary>
        /// Constructor called by the module when it creates a new interface.
        /// </summary>
        /// <param name="m"></param>
	    public NavigationConversion(NavigationModule m)
	    :	base ("Conversion", 0x0001)
		{
            this._self = m;
        }

        #endregion

        #region IConversion Implementation

        /// <summary>
        /// Provide the relative angles to restore the horizontal view.
        /// </summary>
        /// <param name="relative"></param>
        /// <param name="global"></param>
        public void ToGlobal(XNAF.Vector3 relative, ref XNAF.Vector3 global)
        {
            global = XGAE.Helpers.Multiply(this._self.Transform, relative) + this._self.Position;
        }

        /// <summary>
        /// Provide the relative angles to restore the horizontal view.
        /// </summary>
        /// <param name="global"></param>
        /// <param name="relative"></param>
        public void ToRelative(XNAF.Vector3 global, ref XNAF.Vector3 relative)
        {
            relative = XGAE.Helpers.Multiply(this._self.Inverse, (global - this._self.Position));
        }

        #endregion

        #region INavigationInterface Implementation

        // reference to the owner component
        protected NavigationModule _self;

        public NavigationModule Self
        {
            get { return this._self; }
        }

        /// <summary>
        /// Wrappers to retrieve the motion from the module.  
        /// </summary>
        public xBody.Motion.IRelative GetMotion()
        {
            return this._self.Motion;
        }

        /// <summary>
        /// Wrappers to retrieve the physics from the module. 
        /// </summary>
        public xBody.Physics.IRelative GetPhysics()
        {
            return this._self.Physics;
        }

        /// <summary>
        /// Wrappers to retrieve the state from the module.
        /// </summary>
        public xBody.Physics.IState GetState()
        {
            return this._self.State;
        }

        /// <summary>
        /// Wrappers to retrieve the space from the module. 
        /// </summary>
        public xBody.Vision.ISpace GetSpace()
        {
            return this._self.Space;
        }

        /// <summary>
        /// Wrappers to retrieve the visual from the module.
        /// </summary>
        public xBody.Vision.ISymbolic GetVisual()
        {
            return this._self.Visual;
        }

        /// <summary>
        /// Wrappers to retrieve the debug from the module.
        /// </summary>
        public xServ.Debug.IVisual GetDebug()
        {
            return this._self.Debug;
        }

        #endregion
    }

    /// <summary>
    /// Single entry point of control. This interface can be used by most components as a standard
    /// hook, including Brain modules.
    /// </summary>
    class NavigationExecute : Interface, xServ.IExecute, INavigationInterface
    {
        #region C'tors

        /// <summary>
        /// Constructor called by the module when it creates a new interface.
        /// </summary>
        /// <param name="m"></param>
        public NavigationExecute(NavigationModule m)
            : base("Execute", 0x0001)
        {
            this._self = m;
        }

        #endregion

        #region IExecute Implementation

        /// <summary>
        ///Perform the most primitive operation and return within finite time.
        /// </summary>
        public override void Tick()
        {
            this._self.Update();

            if (this._self.Mode == Mode.Stopped)
                return;

            if (this._self.Avoid())
                return;

            switch (this._self.Mode)
            {
                case Mode.Wandering:
                    this._self.Wander();
                    break;
                case Mode.Seeking:
                    this._self.Seek();
                    break;
                case Mode.Fleeing:
                    this._self.Flee();
                    break;
            }
        }

        #endregion

        #region INavigationInterface Implementation

        // reference to the owner component
        protected NavigationModule _self;

        public NavigationModule Self
        {
            get { return this._self; }
        }

        /// <summary>
        /// Wrappers to retrieve the motion from the module.  
        /// </summary>
        public xBody.Motion.IRelative GetMotion()
        {
            return this._self.Motion;
        }

        /// <summary>
        /// Wrappers to retrieve the physics from the module. 
        /// </summary>
        public xBody.Physics.IRelative GetPhysics()
        {
            return this._self.Physics;
        }

        /// <summary>
        /// Wrappers to retrieve the state from the module.
        /// </summary>
        public xBody.Physics.IState GetState()
        {
            return this._self.State;
        }

        /// <summary>
        /// Wrappers to retrieve the space from the module. 
        /// </summary>
        public xBody.Vision.ISpace GetSpace()
        {
            return this._self.Space;
        }

        /// <summary>
        /// Wrappers to retrieve the visual from the module.
        /// </summary>
        public xBody.Vision.ISymbolic GetVisual()
        {
            return this._self.Visual;
        }

        /// <summary>
        /// Wrappers to retrieve the debug from the module.
        /// </summary>
        public xServ.Debug.IVisual GetDebug()
        {
            return this._self.Debug;
        }

        #endregion
    }
}
